package com.gitee.wsl.mathematics.number


interface NumberCalcContainer<T> :Spatial where T:Number/*,T:Comparable<T>*/{
    val zero:T

    val one:T get() = 1 + zero

    val NaN:T

    val POSITIVE_INFINITY:T

    val NEGATIVE_INFINITY:T

    val MAX_VALUE :T

    val MIN_VALUE:T

    override val isNaN: Boolean
        get() = this == NaN

    override val isInfinite: Boolean
        get() = this == POSITIVE_INFINITY || this == NEGATIVE_INFINITY

    override val isFinite: Boolean
        get() = ! isInfinite

    fun sin(a:T): T

    fun cos(a:T): T

    fun abs(a:T): T

    fun sign(a:T): T

    fun ceil(a:T): T

    fun floor(a:T): T

    fun round(a:T): T

    fun sqrt(a:T):T

    fun acos(a:T):T

    fun asin(a:T):T

    fun atan2(a:T,b:T):T

    fun tan(a: T):T

    fun sqr(x: T): T = x * x

    fun norm(x: T, y: T, z: T): T = sqrt(sqr(x) + sqr(y) + sqr(z))

    fun hypot(a:T,b:T):T

    operator fun  Number.plus(x: Number): T

    operator fun  Number.minus(x: Number): T

    operator fun  Number.times(x: Number): T

    operator fun  Number.div(x: Number): T

    operator fun  Number.unaryMinus() : T

    operator fun  Number.unaryPlus() : T

    fun clamp(r:T,a:T,b:T) : T

    operator fun T.rem(a: Number):T

    //operator fun T.rangeTo(other:T):ClosedRange<T>

    //operator fun T.rangeUntil(other:T):OpenEndRange<T>

    fun T.inRange(start:T,end:T):Boolean
    fun T.inRangeOpen(start:T,end:T):Boolean
    //fun T.inOpenRange(start:T,end:T):Boolean

    fun isFuzzyZero(a:T):Boolean

    fun isFuzzyEqual(a:T,b:T):Boolean

    //operator fun  Number.times(x: Number): T

    fun T.divBy(a: Number):T

    fun T.remBy(a: Number):T

    infix fun T.approx(a: T) = isFuzzyEqual(this,a)

    fun T.isApproxZero() = isFuzzyZero(this)

    fun min(a:T,b:T):T


    fun min(a:T,b:T,c:T):T = min(min(a,b),c)

    fun min(a:T,b:T,c:T,d:T):T = min(min(a,b),min(c,d))

    fun min(a:T,b:T,c:T,d:T,f:T):T = min(min(a,b,c,d),f)

    fun max(a:T,b:T):T

    fun max(a:T,b:T,c:T):T = max(max(a,b),c)

    fun max(a:T,b:T,c:T,d:T):T = max(max(a,b),max(c,d))

    fun max(a:T,b:T,c:T,d:T,f:T):T = max(max(a,b,c,d),f)

    fun T.map(start1: T, stop1: T, start2: T, stop2: T, withBounds: Boolean = true): T = mapValue(start1, stop1, start2, stop2, this,withBounds)

    fun mapValue(start1: T, stop1: T, start2: T, stop2: T, value:T, withBounds: Boolean = true): T

    fun mix(left:T,right:T,x:T):T  = left * (one - x) + right * x

}

//fun <T:Number,R> NumberCalcCoainter<T>.run(block:NumberCalcCoainter<T>.()->R) = block()

